
#include <ctype.h>
#include <map>
#include <sstream>

#include "cpp_generator.h"
#include "cpp_generator_helpers.h"
#include "pebble_version.inh"
#include "version.inh"


namespace pebble {

// 工具版本号
std::string Version() {
    std::ostringstream out;
    out << pebble::PebbleVersion::GetVersion() <<
        " " << __TIME__ <<
        " " << __DATE__;
    return out.str();
}

// 生成文件标识
std::string FileNameIdentifier(const std::string& filename) {
    std::string result;
    for (unsigned i = 0; i < filename.size(); i++) {
        char c = filename[i];
        if (isalnum(c)) {
            result.push_back(c);
        } else {
            static char hex[] = "0123456789abcdef";
            result.push_back('_');
            result.push_back(hex[(c >> 4) & 0xf]);
            result.push_back(hex[c & 0xf]);
        }
    }
    return result;
}

// 生成include信息
void PrintIncludes(Printer* printer, const std::vector<std::string>& headers,
                   const Parameters& params) {
    std::map<std::string, std::string> vars;

    vars["l"] = params.use_system_headers ? '<' : '"';
    vars["r"] = params.use_system_headers ? '>' : '"';

    const std::string& s = params.search_path;
    if (!s.empty()) {
        vars["l"] += s;
        if (s[s.size() - 1] != '/') {
            vars["l"] += '/';
        }
    }

    for (std::vector<std::string>::const_iterator it = headers.begin();
        it != headers.end(); it++) {
        vars["h"] = *it;
        printer->Print(vars, "#include $l$$h$$r$\n");
    }
}

// 生成头文件首部
std::string GetHeaderPrologue(File* file, const Parameters& params, const std::string& inh) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    vars["filename"] = file->filename();
    vars["filename_identifier"] = FileNameIdentifier(file->filename());
    vars["filename_base"] = file->filename_without_ext();
    vars["message_header_ext"] = file->message_header_ext();
    std::string tmp_inh(inh);
    pebble::StringUtility::ToUpper(&tmp_inh);
    vars["inh"] = tmp_inh;
    
    printer->Print("// Generated by the Pebble C++ plugin ");
    printer->Print(Version().c_str());
    printer->Print("\n");
    printer->Print("// If you make any local change, they will be lost.\n");
    printer->Print(vars, "// source: $filename$\n");
    
    std::string leading_comments = file->GetLeadingComments();
    if (!leading_comments.empty()) {
        printer->Print("// Original file comments:\n");
        printer->Print(leading_comments.c_str());
        printer->Print("\n");
    }
    printer->Print(vars, "#ifndef _PEBBLE_$filename_identifier$_$inh$_\n");
    printer->Print(vars, "#define _PEBBLE_$filename_identifier$_$inh$_\n");
    printer->Print("\n\n");

    return output;
}

// 生成头文件include部分 + 引用声明
std::string GetHeaderIncludes(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::vector<std::string> headers;
    headers.push_back(file->filename_without_path() + file->service_imp_header_ext()); // filename.rpc.pb.inh
    PrintIncludes(printer.get(), headers, params);
    printer->Print("\n\n");

    if (!file->package().empty()) {
        std::map<std::string, std::string> vars;
        std::vector<std::string> parts = file->package_parts();

        for (std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); it++) {
            vars["part"] = *it;
            printer->Print(vars, "namespace $part$ {\n");
        }
        printer->Print("\n");
    }

    return output;
}

// 生成inh文件include部分 + 引用声明
std::string GetINHeaderIncludes(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    std::vector<std::string> headers;
#ifndef __RPC_CLIENT__
    headers.push_back("framework/pebble_rpc.h");
#else
    headers.push_back("pebble_rpc.h");
#endif
    headers.push_back(file->filename_without_path() + file->message_header_ext()); // filename.pb.h
    PrintIncludes(printer.get(), headers, params);
    printer->Print("\n");

    if (!file->package().empty()) {
        std::vector<std::string> parts = file->package_parts();

        for (std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); it++) {
            vars["part"] = *it;
            printer->Print(vars, "namespace $part$ {\n");
        }
        printer->Print("\n");
    }

    return output;
}

// 生成client接口
void PrintINHeaderClientMethod(
    Printer* printer, const Method* method,
    std::map<std::string, std::string>* vars, bool is_public) {

    if (!is_public) {
        return;
    }

    (*vars)["Method"] = method->name();
    (*vars)["Request"] = method->input_type_name();
    (*vars)["Response"] = method->output_type_name();

    if (method->NoStreaming()) {
#ifndef __RPC_CLIENT__
        // 同步
        printer->Print(*vars,
            "virtual int32_t $Method$(const $Request$& request, $Response$* response) = 0;\n");
        // 并行
        printer->Print(*vars,
            "virtual int32_t Parallel$Method$(const $Request$& request,"
            " int32_t* ret_code, $Response$* response,"
            " uint32_t* num_called, uint32_t* num_parallel) = 0;\n");
#endif
        // 异步
        printer->Print(*vars,
            "virtual void $Method$(const $Request$& request, "
            "const cxx::function<void(int32_t ret_code, const $Response$& response)>& cb) = 0;\n");
    } else if (method->ClientOnlyStreaming()) {
        printer->Print(*vars, "// TODO: ClientOnlyStreaming for $Method$\n");
    } else if (method->ServerOnlyStreaming()) {
        printer->Print(*vars, "// TODO: ServerOnlyStreaming for $Method$\n");
    } else if (method->BidiStreaming()) {
        printer->Print(*vars, "// TODO: BidiStreaming for $Method$\n");
    }
}

// 生成client接口定义
void PrintHeaderClientMethod(
    Printer* printer, const Method* method,
    std::map<std::string, std::string>* vars, bool is_public) {
    (*vars)["Method"] = method->name();
    (*vars)["Request"] = method->input_type_name();
    (*vars)["Response"] = method->output_type_name();
    if (is_public) {
        if (!method->GetLeadingComments().empty()) {
            printer->Print(method->GetLeadingComments().c_str());
            printer->Print("\n");
        }
        if (!method->GetTrailingComments().empty()) {
            printer->Print(method->GetTrailingComments().c_str());
            printer->Print("\n");
        }
        if (method->NoStreaming()) {
#ifndef __RPC_CLIENT__
            // 同步
            printer->Print(*vars, "/* $Method$同步调用，返回0时调用成功，非0失败 */\n");
            printer->Print(*vars,
                "virtual int32_t $Method$(const $Request$& request, $Response$* response);\n");
            // 并行
            printer->Print(*vars, "/* $Method$并行调用，一般通过Pebble并行模块(pebble::AddCall/WhenAll)来使用此接口 */\n");
            printer->Print(*vars,
                "virtual int32_t Parallel$Method$(const $Request$& request,"
                " int32_t* ret_code, $Response$* response,"
                " uint32_t* num_called, uint32_t* num_parallel);\n");
#endif
            // 异步
            printer->Print(*vars, "/* $Method$异步调用，回调函数第一个参数为RPC调用结果，0为成功，非0失败 */\n");
            printer->Print(*vars,
                "virtual void $Method$(const $Request$& request, "
                "const cxx::function<void(int32_t ret_code, const $Response$& response)>& cb);\n");
        } else if (method->ClientOnlyStreaming()) {
            printer->Print(*vars, "// TODO: ClientOnlyStreaming for $Method$\n");
        } else if (method->ServerOnlyStreaming()) {
            printer->Print(*vars, "// TODO: ServerOnlyStreaming for $Method$\n");
        } else if (method->BidiStreaming()) {
            printer->Print(*vars, "// TODO: BidiStreaming for $Method$\n");
        }
    } else {
        if (method->NoStreaming()) {
#ifndef __RPC_CLIENT__
            printer->Print(*vars,
                "int32_t recv_$Method$_sync(int32_t ret, const uint8_t* buff, uint32_t buff_len,"
                " $Response$* response);\n");
            printer->Print(*vars,
                "int32_t recv_$Method$_parallel(int32_t ret, const uint8_t* buff, uint32_t buff_len,"
                " int32_t* ret_code, $Response$* response);\n");
#endif
            printer->Print(*vars,
                "int32_t recv_$Method$(int32_t ret, const uint8_t* buff, uint32_t buff_len,"
                " cxx::function<void(int ret_code, const $Response$& response)>& cb);\n");
        } else if (method->ClientOnlyStreaming()) {
            printer->Print(*vars, "// TODO: ClientOnlyStreaming for $Method$\n");
        } else if (method->ServerOnlyStreaming()) {
            printer->Print(*vars, "// TODO: ServerOnlyStreaming for $Method$\n");
        } else if (method->BidiStreaming()) {
            printer->Print(*vars, "// TODO: BidiStreaming for $Method$\n");
        }
    }
}

// 生成服务端接口，是用户需要实现的部分
void PrintHeaderServerMethod(
    Printer* printer, const Method* method,
    std::map<std::string, std::string>* vars) {

    (*vars)["Method"] = method->name();
    (*vars)["Request"] = method->input_type_name();
    (*vars)["Response"] = method->output_type_name();

    if (!method->GetLeadingComments().empty()) {
        printer->Print(method->GetLeadingComments().c_str());
        printer->Print("\n");
    }
    if (!method->GetTrailingComments().empty()) {
        printer->Print(method->GetTrailingComments().c_str());
        printer->Print("\n");
    }
    if (method->NoStreaming()) {
        printer->Print(*vars,
            "virtual void $Method$(const $Request$& request,"
            " cxx::function<void(int32_t ret_code, const $Response$& response)>& rsp) = 0;\n");
    } else if (method->ClientOnlyStreaming()) {
        printer->Print(*vars, "// TODO: ClientOnlyStreaming for $Method$\n");
    } else if (method->ServerOnlyStreaming()) {
        printer->Print(*vars, "// TODO: ServerOnlyStreaming for $Method$\n");
    } else if (method->BidiStreaming()) {
        printer->Print(*vars, "// TODO: BidiStreaming for $Method$\n");
    }
}

// 生成服务端骨架代码接口定义
void PrintINHeaderServerMethod(
    Printer* printer, const Method* method,
    std::map<std::string, std::string> *vars) {
    (*vars)["Method"] = method->name();
    (*vars)["Request"] = method->input_type_name();
    (*vars)["Response"] = method->output_type_name();
  
    if (method->NoStreaming()) {
        printer->Print(*vars,
            "int32_t process_$Method$(const uint8_t* buff, uint32_t buff_len,"
            " cxx::function<int32_t(int32_t ret, const uint8_t* buff, uint32_t buff_len)>& rsp);\n");
        printer->Print(*vars,
            "void return_$Method$(cxx::function<int32_t(int32_t ret, const uint8_t* buff, uint32_t buff_len)>& rsp,"
            " int32_t ret_code, const $Response$& response);\n");
    } else if (method->ClientOnlyStreaming()) {
        printer->Print(*vars, "// TODO: ClientOnlyStreaming for $Method$\n");
    } else if (method->ServerOnlyStreaming()) {
        printer->Print(*vars, "// TODO: ServerOnlyStreaming for $Method$\n");
    } else if (method->BidiStreaming()) {
        printer->Print(*vars, "// TODO: BidiStreaming for $Method$\n");
    }
}

// 生成桩代码接口和服务端骨架代码定义，输出到proto_service.inh中
void PrintINHeaderService(Printer* printer, const Service* service,
    std::map<std::string, std::string>* vars) {
    (*vars)["Service"] = service->name();

    // 生成客户端接口类
    printer->Print(*vars, "class $Service$ClientInterface {\n"
        "public:\n");
    printer->Indent();
    printer->Print(*vars, "virtual ~$Service$ClientInterface() {}\n\n");
    for (int i = 0; i < service->method_count(); ++i) {
        PrintINHeaderClientMethod(printer, service->method(i).get(), vars, true);
    }
    printer->Outdent();
    printer->Print("};\n\n");

    // 生成客户端桩实现类
    printer->Print(*vars, "class $Service$ClientImp {\n"
        "friend class $Service$Client;\n"
        "public:\n");

    printer->Indent();
    printer->Print(*vars, "$Service$ClientImp(::pebble::PebbleRpc* rpc);\n");
    printer->Print(*vars, "virtual ~$Service$ClientImp();\n\n");
    printer->Print("int64_t GetHandle();\n\n");

    for (int i = 0; i < service->method_count(); ++i) {
        PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
    }
    printer->Outdent();

    printer->Print("\nprivate:\n");
    printer->Indent();
    printer->Print("::pebble::PebbleRpc* m_client;\n");
    printer->Print("int64_t m_handle;\n");
    printer->Print("cxx::function<int64_t(uint64_t)> m_route_func;\n");
    printer->Print("uint64_t m_route_key;\n");
#ifndef __RPC_CLIENT__
    printer->Print("std::string m_channel_name;\n");
#endif
    printer->Print("cxx::unordered_map<std::string, uint32_t> m_methods;\n");
    printer->Outdent();

    printer->Print("};\n\n");

    // 生成服务端骨架类定义
    printer->Print(*vars, "class $Service$ServerInterface;\n");
    printer->Print(*vars, "class __$Service$Skeleton : public ::pebble::IPebbleRpcService {\n"
        "protected:\n");
    printer->Indent();
    printer->Print("::pebble::PebbleRpc* m_server;\n\n");
    printer->Outdent();
    
    printer->Print("private:\n");
    printer->Indent();
    printer->Print(*vars, "$Service$ServerInterface* m_iface;\n\n");
    printer->Outdent();

    printer->Print("private:\n");
    printer->Indent();
    for (int i = 0; i < service->method_count(); ++i) {
        PrintINHeaderServerMethod(printer, service->method(i).get(), vars);
    }
    printer->Outdent();

    printer->Print("\npublic:\n");
    printer->Indent();
    printer->Print(*vars, "__$Service$Skeleton(::pebble::PebbleRpc* server, $Service$ServerInterface* iface);\n");
    printer->Print(*vars, "virtual ~__$Service$Skeleton() {}\n");
    printer->Print("virtual int32_t RegisterServiceFunction();\n");
    printer->Print(*vars, "virtual std::string Name() { return \"$Service$\"; }\n");
    printer->Outdent();
    
    printer->Print("};\n");
}

// 生成桩代码定义和服务端接口类，输出到proto_service.h中
void PrintHeaderService(Printer* printer, const Service* service,
    std::map<std::string, std::string>* vars) {
    (*vars)["Service"] = service->name();

    // 生成客户端类定义
    if (!service->GetLeadingComments().empty()) {
        printer->Print(service->GetLeadingComments().c_str());
        printer->Print("\n");
    }
    if (!service->GetTrailingComments().empty()) {
        printer->Print(service->GetTrailingComments().c_str());
        printer->Print("\n");
    }
    printer->Print(*vars, "class $Service$Client : public $Service$ClientInterface {\n"
        "public:\n"
        "    /* IDL定义接口，每个接口对应生成3个方法，分别是同步调用、并行调用、异步调用 */\n\n");

    printer->Indent();
    for (int i = 0; i < service->method_count(); ++i) {
        PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
    }
    printer->Outdent();

    printer->Print("\npublic:\n"
        "    /* 功能接口 */\n\n");
    printer->Indent();
    printer->Print(*vars, "$Service$Client(::pebble::PebbleRpc* rpc);\n");
    printer->Print(*vars, "virtual ~$Service$Client();\n\n");
    printer->Print("/* 设置连接句柄，RPC请求通过此句柄对应的连接发送 */\n");
    printer->Print("void SetHandle(int64_t handle);\n\n");
    printer->Print("/* 设置路由函数，连接的选择交给路由回调函数处理，RPC请求通过路由回调函数选择的连接发送 */\n");
    printer->Print("/* 设置路由回调函数后，不再使用SetHandle设置的连接句柄 */\n");
    printer->Print("void SetRouteFunction(const cxx::function<int64_t(uint64_t key)>& route_callback);\n\n");
    printer->Print("/* 设置路由key，如使用取模或哈希路由策略时使用 */\n");
    printer->Print("void SetRouteKey(uint64_t route_key);\n\n");
#ifndef __RPC_CLIENT__
    printer->Print("/* 设置广播的频道名字，设置了频道后Client将所有的RPC请求按广播处理，广播至channel_name */\n");
    printer->Print("void SetBroadcast(const std::string& channel_name);\n\n");
#endif
    printer->Print("/* 设置RPC请求超时时间(单位ms)，未指定方法名时对所有方法生效，指定方法名时只对指定方法生效，默认的超时时间为10s */\n");
    printer->Print("int SetTimeout(uint32_t timeout_ms, const char* method_name = NULL);\n\n");

    printer->Outdent();

    printer->Print("\nprivate:\n");
    printer->Indent();
    printer->Print(*vars, "$Service$ClientImp* m_imp;\n");
    printer->Outdent();

    printer->Print("};\n\n");
    

    // 生成服务端接口类
    if (!service->GetLeadingComments().empty()) {
        printer->Print(service->GetLeadingComments().c_str());
        printer->Print("\n");
    }
    if (!service->GetTrailingComments().empty()) {
        printer->Print(service->GetTrailingComments().c_str());
        printer->Print("\n");
    }
    printer->Print(*vars, "class $Service$ServerInterface {\n"
        "public:\n");
    printer->Indent();
    printer->Print(*vars, "virtual ~$Service$ServerInterface() {}\n\n");
    for (int i = 0; i < service->method_count(); ++i) {
        PrintHeaderServerMethod(printer, service->method(i).get(), vars);
    }
    printer->Print(*vars, "\n\ntypedef $Service$ServerInterface __InterfaceType;\n");
    printer->Outdent();
    printer->Print("};\n\n");
}

// 生成框架使用的生成server骨架代码模版方法，输出到proto_service.h中
void PrintHeaderServiceEx(Printer* printer, const Service* service,
    std::map<std::string, std::string>* vars) {
    (*vars)["Service"] = service->name();

    // 生成内部使用模版方法
    printer->Print("/* 内部使用，用户无需关注 */\n");
    printer->Print("namespace pebble {\n");
    printer->Print("template<typename Class> class GenServiceHandler;\n\n");
    printer->Print("template<>\n");
    printer->Print(*vars, "class GenServiceHandler< $complete_ns$::$Service$ServerInterface> {\n");
    printer->Print("public:\n");

    printer->Indent();
    printer->Print(*vars, "cxx::shared_ptr< ::pebble::IPebbleRpcService> operator() ("
        "::pebble::PebbleRpc* rpc, $complete_ns$::$Service$ServerInterface *iface) {\n");
    printer->Indent();
    printer->Print("cxx::shared_ptr< ::pebble::IPebbleRpcService> service_handler(\n");
    printer->Indent();
    printer->Print(*vars, "new $complete_ns$::__$Service$Skeleton(rpc, iface));\n");
    printer->Outdent();
    printer->Print("return service_handler;\n");
    printer->Outdent();
    printer->Print("}\n");
    printer->Outdent();
    printer->Print("};\n");
    printer->Print("} // namespace pebble\n");
}

// 获取服务定义头文件内容
std::string GetHeaderServices(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    vars["Package"] = file->package();
    if (!file->package().empty()) {
        vars["Package"].append(".");

        std::string complete_ns;
        std::vector<std::string> parts = file->package_parts();
        for (std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); it++) {
            if (it != parts.begin()) {
                complete_ns.append("::");
            }
            complete_ns.append(*it);
        }
        vars["complete_ns"] = complete_ns;
    }

    if (!params.services_namespace.empty()) {
        vars["services_namespace"] = params.services_namespace;
        printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
    }

    for (int i = 0; i < file->service_count(); ++i) {
        PrintHeaderService(printer.get(), file->service(i).get(), &vars);
        printer->Print("\n");
    }

    if (!params.services_namespace.empty()) {
        printer->Print(vars, "}  // namespace $services_namespace$\n\n");
    }

    return output;
}

// 获取服务内部定义头文件内容
std::string GetINHeaderService(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    vars["Package"] = file->package();
    if (!file->package().empty()) {
        vars["Package"].append(".");
    }

    if (!params.services_namespace.empty()) {
        vars["services_namespace"] = params.services_namespace;
        printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
    }

    for (int i = 0; i < file->service_count(); ++i) {
        PrintINHeaderService(printer.get(), file->service(i).get(), &vars);
        printer->Print("\n");
    }

    if (!params.services_namespace.empty()) {
        printer->Print(vars, "}  // namespace $services_namespace$\n\n");
    }

    return output;
}

// 生成头文件尾部
std::string GetHeaderEpilogue(File* file, const Parameters& params, const std::string& inh) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    vars["filename"] = file->filename();
    vars["filename_identifier"] = FileNameIdentifier(file->filename());
    std::string tmp_inh(inh);
    pebble::StringUtility::ToUpper(&tmp_inh);
    vars["inh"] = tmp_inh;

    std::string complete_ns;
    if (!file->package().empty()) {
        std::vector<std::string> parts = file->package_parts();

        for (std::vector<std::string>::reverse_iterator it = parts.rbegin();
            it != parts.rend(); it++) {
            vars["part"] = *it;
            printer->Print(vars, "} // namespace $part$\n");
        }
        printer->Print("\n");

        for (std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); it++) {
            complete_ns.append("::");
            complete_ns.append(*it);
        }
    }
    vars["complete_ns"] = complete_ns;

    if (inh == "h") {
        for (int i = 0; i < file->service_count(); ++i) {
            PrintHeaderServiceEx(printer.get(), file->service(i).get(), &vars);
            printer->Print("\n");
        }
    }

    printer->Print("\n\n");
    printer->Print(vars, "#endif // _PEBBLE_$filename_identifier$_$inh$H_\n");

    printer->Print(file->GetTrailingComments().c_str());

    return output;
}

// 生成源文件首部
std::string GetSourcePrologue(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    vars["filename"] = file->filename();

    printer->Print("// Generated by the Pebble C++ plugin ");
    printer->Print(Version().c_str());
    printer->Print("\n");
    printer->Print("// If you make any local change, they will be lost.\n");
    printer->Print(vars, "// source: $filename$\n\n");

    return output;
}

// 生成源文件include部分
std::string GetSourceIncludes(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::vector<std::string> headers;
    headers.push_back(file->filename_without_path() + file->service_header_ext()); // filename.rpc.pb.h
    PrintIncludes(printer.get(), headers, params);
    printer->Print("\n");

    if (!file->package().empty()) {
        std::map<std::string, std::string> vars;
        std::vector<std::string> parts = file->package_parts();

        for (std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); it++) {
            vars["part"] = *it;
            printer->Print(vars, "namespace $part$ {\n");
        }
    }

    printer->Print("\n");

    return output;
}

// 生成客户端接口实现
void PrintSourceClientMethod(Printer* printer, const Method* method,
                             std::map<std::string, std::string>* vars, bool is_public) {
    if (!method->NoStreaming()) {
        printer->Print("// TODO: unsupport Streaming Method.");
        return;
    }

    (*vars)["Method"] = method->name();
    (*vars)["Request"] = method->input_type_name();
    (*vars)["Response"] = method->output_type_name();

    if (is_public) {
#ifndef __RPC_CLIENT__
        // 同步调用
        printer->Print(*vars, "int32_t $Service$Client::$Method$("
            "const $Request$& request, $Response$* response) {\n");
        printer->Indent();

        printer->Print("::pebble::RpcHead __head;\n");
        printer->Print(*vars, "__head.m_function_name.assign(\"$Service$:$Method$\");\n");
        printer->Print("__head.m_message_type = ::pebble::kRPC_CALL;\n");
        printer->Print("__head.m_session_id = m_imp->m_client->GenSessionId();\n\n");

        printer->Print("int __size = request.ByteSize();\n");
        printer->Print("uint8_t* __buff = m_imp->m_client->GetBuffer(__size);\n");
        printer->Print("if (__buff == NULL) {\n");
        printer->Indent();
        printer->Print("return ::pebble::kPEBBLE_RPC_INSUFFICIENT_MEMORY;\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("if (!request.SerializeToArray(__buff, __size)) {\n");
        printer->Indent();
        printer->Print("return ::pebble::kRPC_ENCODE_FAILED;\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("if (m_imp->m_channel_name.empty()) {\n");
        printer->Indent();
        printer->Print(*vars, "::pebble::OnRpcResponse on_rsp = cxx::bind(&$Service$ClientImp::recv_$Method$_sync, m_imp,\n");
        printer->Print("    cxx::placeholders::_1, cxx::placeholders::_2, cxx::placeholders::_3, response);\n");
        printer->Print(*vars, "return m_imp->m_client->SendRequestSync(m_imp->GetHandle(), __head, __buff, __size, on_rsp, m_imp->m_methods[\"$Method$\"]);\n");
        printer->Outdent();
        printer->Print("} else {\n");
        printer->Indent();
        printer->Print("return m_imp->m_client->BroadcastRequest(m_imp->m_channel_name, __head, __buff, __size);\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Outdent();
        printer->Print("}\n\n");

        // 并行调用
        printer->Print(*vars,
            "int32_t $Service$Client::Parallel$Method$(const $Request$& request,"
            " int32_t* ret_code, $Response$* response,"
            " uint32_t* num_called, uint32_t* num_parallel) {\n");
        printer->Indent();

        printer->Print("::pebble::RpcHead __head;\n");
        printer->Print(*vars, "__head.m_function_name.assign(\"$Service$:$Method$\");\n");
        printer->Print("__head.m_message_type = ::pebble::kRPC_CALL;\n");
        printer->Print("__head.m_session_id = m_imp->m_client->GenSessionId();\n\n");

        printer->Print("int __size = request.ByteSize();\n");
        printer->Print("uint8_t* __buff = m_imp->m_client->GetBuffer(__size);\n");
        printer->Print("if (__buff == NULL) {\n");
        printer->Indent();
        printer->Print("return ::pebble::kPEBBLE_RPC_INSUFFICIENT_MEMORY;\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("if (!request.SerializeToArray(__buff, __size)) {\n");
        printer->Indent();
        printer->Print("return ::pebble::kRPC_ENCODE_FAILED;\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("if (m_imp->m_channel_name.empty()) {\n");
        printer->Indent();
        printer->Print(*vars, "::pebble::OnRpcResponse on_rsp = cxx::bind(&$Service$ClientImp::recv_$Method$_parallel, m_imp,\n");
        printer->Print("    cxx::placeholders::_1, cxx::placeholders::_2, cxx::placeholders::_3, ret_code, response);\n");
        printer->Print(*vars, "m_imp->m_client->SendRequestParallel(m_imp->GetHandle(), __head, __buff, __size, on_rsp, m_imp->m_methods[\"$Method$\"], ret_code, num_called, num_parallel);\n");
        printer->Outdent();
        printer->Print("} else {\n");
        printer->Indent();
        printer->Print("*ret_code = m_imp->m_client->BroadcastRequest(m_imp->m_channel_name, __head, __buff, __size);\n");
        printer->Print("--(*num_called);\n");
        printer->Print("--(*num_parallel);\n");
        printer->Outdent();
        printer->Print("}\n\n");
        printer->Print("return *ret_code;\n");

        printer->Outdent();
        printer->Print("}\n\n");
#endif
        // 异步调用
        printer->Print(*vars,
            "void $Service$Client::$Method$(const $Request$& request, "
            "const cxx::function<void(int32_t ret_code, const $Response$& response)>& cb) {\n");
        printer->Indent();

        printer->Print("::pebble::RpcHead __head;\n");
        printer->Print(*vars, "__head.m_function_name.assign(\"$Service$:$Method$\");\n");
        printer->Print("__head.m_message_type = ::pebble::kRPC_CALL;\n");
        printer->Print("__head.m_session_id = m_imp->m_client->GenSessionId();\n\n");

        printer->Print("int __size = request.ByteSize();\n");
        printer->Print("uint8_t* __buff = m_imp->m_client->GetBuffer(__size);\n");
        printer->Print("if (__buff == NULL) {\n");
        printer->Indent();
        printer->Print(*vars, "$Response$ __response;\n");
        printer->Print("cb(::pebble::kPEBBLE_RPC_INSUFFICIENT_MEMORY, __response);\n");
        printer->Print("return;\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("if (!request.SerializeToArray(__buff, __size)) {\n");
        printer->Indent();
        printer->Print(*vars, "$Response$ __response;\n");
        printer->Print("cb(::pebble::kRPC_ENCODE_FAILED, __response);\n");
        printer->Print("return;\n");
        printer->Outdent();
        printer->Print("}\n\n");

#ifndef __RPC_CLIENT__
        printer->Print("if (m_imp->m_channel_name.empty()) {\n");
        printer->Indent();
#endif
        printer->Print(*vars, "::pebble::OnRpcResponse on_rsp = cxx::bind(&$Service$ClientImp::recv_$Method$, m_imp,\n");
        printer->Print("    cxx::placeholders::_1, cxx::placeholders::_2, cxx::placeholders::_3, cb);\n");
        printer->Print(*vars, "int32_t __ret = m_imp->m_client->SendRequest(m_imp->GetHandle(), __head, __buff, __size, on_rsp, m_imp->m_methods[\"$Method$\"]);\n");
        printer->Print("if (__ret != ::pebble::kRPC_SUCCESS) {\n");
        printer->Indent();
        printer->Print(*vars, "$Response$ __response;\n");
        printer->Print("cb(__ret, __response);\n");
        printer->Print("return;\n");
        printer->Outdent();
        printer->Print("}\n");
#ifndef __RPC_CLIENT__
        printer->Outdent();
        printer->Print("} else {\n");
        printer->Indent();
        printer->Print("int32_t __ret = m_imp->m_client->BroadcastRequest(m_imp->m_channel_name, __head, __buff, __size);\n");
        printer->Print("if (__ret != ::pebble::kRPC_SUCCESS) {\n");
        printer->Indent();
        printer->Print(*vars, "$Response$ __response;\n");
        printer->Print("cb(__ret, __response);\n");
        printer->Print("return;\n");
        printer->Outdent();
        printer->Print("}\n");
        printer->Outdent();
        printer->Print("}\n\n");
#endif

        printer->Outdent();
        printer->Print("}\n\n");

    } else {
#ifndef __RPC_CLIENT__
        // 同步调用响应处理
        printer->Print(*vars,
            "int32_t $Service$ClientImp::recv_$Method$_sync(int32_t ret, const uint8_t* buff, uint32_t buff_len,"
            " $Response$* response) {\n");
        printer->Indent();

        printer->Print("if (ret != ::pebble::kRPC_SUCCESS) {\n");
        printer->Indent();
        printer->Print("if (0 == buff_len) {\n");
        printer->Indent();
        printer->Print("return ret;\n");
        printer->Outdent();
        printer->Print("}\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("if (!response->ParseFromArray((const void*)buff, buff_len)) {\n");
        printer->Indent();
        printer->Print("return ::pebble::kRPC_DECODE_FAILED;\n");
        printer->Outdent();
        printer->Print("}\n\n");

        printer->Print("return ret != ::pebble::kRPC_SUCCESS ? ret : ::pebble::kRPC_SUCCESS;\n");

        printer->Outdent();
        printer->Print("}\n\n");

        // 并行调用响应处理
        printer->Print(*vars,
            "int32_t $Service$ClientImp::recv_$Method$_parallel(int32_t ret, const uint8_t* buff, uint32_t buff_len,"
            " int32_t* ret_code, $Response$* response) {\n");
        printer->Indent();

        printer->Print(*vars, "*ret_code = recv_$Method$_sync(ret, buff, buff_len, response);\n");
        printer->Print("return *ret_code;\n");

        printer->Outdent();
        printer->Print("}\n\n");
#endif
        // 异步调用响应处理
        printer->Print(*vars,
            "int32_t $Service$ClientImp::recv_$Method$(int32_t ret, const uint8_t* buff, uint32_t buff_len,"
            " cxx::function<void(int ret_code, const $Response$& response)>& cb) {\n");
        printer->Indent();

        printer->Print(*vars, "$Response$ __response;\n");
        printer->Print("if (ret != ::pebble::kRPC_SUCCESS) {\n");
        printer->Indent();
        printer->Print("if (0 == buff_len) {\n");
        printer->Indent();
        printer->Print("cb(ret, __response);\n");
        printer->Print("return ret;\n");
        printer->Outdent();
        printer->Print("}\n");
        printer->Outdent();
        printer->Print("}\n");

        printer->Print("if (!__response.ParseFromArray((const void*)buff, buff_len)) {\n");
        printer->Indent();
        printer->Print("cb(::pebble::kRPC_DECODE_FAILED, __response);\n");
        printer->Print("return ::pebble::kRPC_DECODE_FAILED;\n");
        printer->Outdent();
        printer->Print("}\n");

        printer->Print("cb(ret != ::pebble::kRPC_SUCCESS ? ret : ::pebble::kRPC_SUCCESS, __response);\n");
        printer->Print("return ret != ::pebble::kRPC_SUCCESS ? ret : ::pebble::kRPC_SUCCESS;\n");

        printer->Outdent();
        printer->Print("}\n\n");
    }
}

// 生成服务端接口实现
void PrintSourceServerMethod(Printer* printer, const Method* method,
                             std::map<std::string, std::string>* vars) {
    if (!method->NoStreaming()) {
        printer->Print("// TODO: unsupport Streaming Method.");
        return;
    }

    (*vars)["Method"] = method->name();
    (*vars)["Request"] = method->input_type_name();
    (*vars)["Response"] = method->output_type_name();

    printer->Print(*vars,
        "int32_t __$Service$Skeleton::process_$Method$(const uint8_t* buff, uint32_t buff_len,"
        " cxx::function<int32_t(int32_t ret, const uint8_t* buff, uint32_t buff_len)>& rsp) {\n");
    printer->Indent();

    printer->Print(*vars, "$Request$ __request;\n");
    printer->Print("if (!__request.ParseFromArray((const void*)buff, buff_len)) {\n");
    printer->Indent();
    printer->Print("rsp(::pebble::kPEBBLE_RPC_DECODE_BODY_FAILED, NULL, 0);\n");
    printer->Print("return ::pebble::kPEBBLE_RPC_DECODE_BODY_FAILED;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print(*vars, "cxx::function<void(int32_t ret_code, const $Response$& response)> __rsp =\n");
    printer->Print(*vars, "    cxx::bind(&__$Service$Skeleton::return_$Method$, this,\n");
    printer->Print("        rsp, cxx::placeholders::_1, cxx::placeholders::_2);\n\n");

    printer->Print(*vars, "m_iface->$Method$(__request, __rsp);\n\n");
    printer->Print("return ::pebble::kRPC_SUCCESS;\n");

    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print(*vars,
        "void __$Service$Skeleton::return_$Method$(cxx::function<int32_t(int32_t ret, const uint8_t* buff, uint32_t buff_len)>& rsp,"
        " int32_t ret_code, const $Response$& response) {\n");
    printer->Indent();

    printer->Print("int __size = response.ByteSize();\n");
    printer->Print("uint8_t* __buff = m_server->GetBuffer(__size);\n");
    printer->Print("if (__buff == NULL) {\n");
    printer->Indent();
    printer->Print("rsp(::pebble::kPEBBLE_RPC_INSUFFICIENT_MEMORY, NULL, 0);\n");
    printer->Print("return;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print("if (!response.SerializeToArray(__buff, __size)) {\n");
    printer->Indent();
    printer->Print("rsp(::pebble::kPEBBLE_RPC_ENCODE_BODY_FAILED, NULL, 0);\n");
    printer->Print("return;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print("rsp(ret_code, __buff, __size);\n");

    printer->Outdent();
    printer->Print("}\n\n");
}

// 生成服务实现
void PrintSourceService(Printer* printer, const Service* service,
                        std::map<std::string, std::string> *vars) {
    (*vars)["Service"] = service->name();

    // 生成客户端桩代码
    printer->Print(*vars, "$Service$Client::$Service$Client(::pebble::PebbleRpc* rpc) {\n");
    printer->Indent();
    printer->Print(*vars, "m_imp = new $Service$ClientImp(rpc);\n");
    printer->Outdent();
    printer->Print("}\n\n");
    
    printer->Print(*vars, "$Service$Client::~$Service$Client() { delete m_imp; }\n\n");

    printer->Print(*vars, "void $Service$Client::SetHandle(int64_t handle) {\n");
    printer->Indent();
    printer->Print("m_imp->m_handle = handle;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print(*vars, "void $Service$Client::SetRouteFunction(const cxx::function<int64_t(uint64_t key)>& route_callback) {\n");
    printer->Indent();
    printer->Print("m_imp->m_route_func = route_callback;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print(*vars, "void $Service$Client::SetRouteKey(uint64_t route_key) {\n");
    printer->Indent();
    printer->Print("m_imp->m_route_key = route_key;\n");
    printer->Outdent();
    printer->Print("}\n\n");
#ifndef __RPC_CLIENT__
    printer->Print(*vars, "void $Service$Client::SetBroadcast(const std::string& channel_name) {\n");
    printer->Indent();
    printer->Print("m_imp->m_channel_name = channel_name;\n");
    printer->Outdent();
    printer->Print("}\n\n");
#endif
    printer->Print(*vars, "int $Service$Client::SetTimeout(uint32_t timeout_ms, const char* method_name) {\n");
    printer->Indent();

    // 指定方法名
    printer->Print("if (method_name != NULL) {\n");
    printer->Indent();
    printer->Print("cxx::unordered_map<std::string, uint32_t>::iterator it = m_imp->m_methods.find(method_name);\n");
    printer->Print("if (it == m_imp->m_methods.end()) {\n");
    printer->Indent();
    printer->Print("return pebble::kRPC_UNSUPPORT_FUNCTION_NAME;\n");
    printer->Outdent();
    printer->Print("}\n");
    printer->Print("it->second = timeout_ms;\n");
    printer->Print("return 0;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    // 未指定方法名
    printer->Print("for (cxx::unordered_map<std::string, uint32_t>::iterator it = m_imp->m_methods.begin(); it != m_imp->m_methods.end(); ++it) {\n");
    printer->Indent();
    printer->Print("it->second = timeout_ms;\n");
    printer->Outdent();
    printer->Print("}\n\n");
    printer->Print("return 0;");

    printer->Print("\n");
    printer->Outdent();
    printer->Print("}\n\n");

    for (int i = 0; i < service->method_count(); ++i) {
        PrintSourceClientMethod(printer, service->method(i).get(), vars, true);
    }

    // 生成客户端桩实现类代码
    printer->Print(*vars, "$Service$ClientImp::$Service$ClientImp(::pebble::PebbleRpc* rpc) {\n");
    printer->Indent();
    printer->Print("m_client    = rpc;\n");
    printer->Print("m_route_key = 0;\n");
    
    std::map<std::string, std::string> methods;
    for (int i = 0; i < service->method_count(); ++i) {
        methods["Method"] = service->method(i)->name();
        printer->Print(methods, "m_methods[\"$Method$\"] = 10000;\n");
    }
    printer->Outdent();
    printer->Print("}\n\n");
    
    printer->Print(*vars, "$Service$ClientImp::~$Service$ClientImp() {}\n\n");

    printer->Print(*vars, "int64_t $Service$ClientImp::GetHandle() {\n");
    printer->Indent();
    printer->Print("if (m_route_func) {\n");
    printer->Indent();
    printer->Print("return m_route_func(m_route_key);\n");
    printer->Outdent();
    printer->Print("}\n\n");
    printer->Print("return m_handle;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    for (int i = 0; i < service->method_count(); ++i) {
        PrintSourceClientMethod(printer, service->method(i).get(), vars, false);
    }

    // 生成服务端骨架代码
    printer->Print(*vars, "__$Service$Skeleton::__$Service$Skeleton("
        "::pebble::PebbleRpc* server, $Service$ServerInterface* iface) {\n");
    printer->Indent();
    printer->Print("m_server = server;\n");
    printer->Print("m_iface  = iface;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print(*vars, "int32_t __$Service$Skeleton::RegisterServiceFunction() {\n");
    printer->Indent();

    printer->Print("if (!m_server) {\n");
    printer->Indent();
    printer->Print("return ::pebble::kRPC_INVALID_PARAM;\n");
    printer->Outdent();
    printer->Print("}\n\n");

    printer->Print("::pebble::OnRpcRequest cb;\n");
    printer->Print("int32_t ret = ::pebble::kRPC_SUCCESS;\n\n");

    for (int i = 0; i < service->method_count(); ++i) {
        (*vars)["Method"] = service->method(i)->name();
        printer->Print(*vars, "cb = cxx::bind(&__$Service$Skeleton::process_$Method$, this,\n");
        printer->Print("    cxx::placeholders::_1, cxx::placeholders::_2, cxx::placeholders::_3);\n");
        printer->Print(*vars, "ret = m_server->AddOnRequestFunction(\"$Service$:$Method$\", cb);\n");
        printer->Print("if (ret != ::pebble::kRPC_SUCCESS) {\n");
        printer->Indent();
        printer->Print("return ret;\n");
        printer->Outdent();
        printer->Print("}\n\n");
    }

    printer->Print("return ret;\n");

    printer->Outdent();
    printer->Print("}\n\n");

    for (int i = 0; i < service->method_count(); ++i) {
        PrintSourceServerMethod(printer, service->method(i).get(), vars);
    }
}

// 生成服务实现
std::string GetSourceServices(File* file, const Parameters& params) {
    std::string output;

    cxx::shared_ptr<Printer> printer = file->CreatePrinter(&output);
    std::map<std::string, std::string> vars;

    vars["Package"] = file->package();
    if (!file->package().empty()) {
        vars["Package"].append(".");
    }
    if (!params.services_namespace.empty()) {
        vars["ns"] = params.services_namespace + "::";
        vars["prefix"] = params.services_namespace;
    } else {
        vars["ns"] = "";
        vars["prefix"] = "";
    }

    for (int i = 0; i < file->service_count(); ++i) {
        PrintSourceService(printer.get(), file->service(i).get(), &vars);
        printer->Print("\n");
    }

    return output;
}

// 生成源文件尾部
std::string GetSourceEpilogue(File* file, const Parameters& params) {
    std::string temp;
    if (!file->package().empty()) {
        std::vector<std::string> parts = file->package_parts();

        for (std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); it++) {
            temp.append("} // namespace ");
            temp.append(*it);
            temp.append("\n");
        }
        temp.append("\n");
    }

    return temp;
}

} // namespace pebble
